#ifndef L_VERSION
#   define L_VERSION 1120104
#endif
#include <llib.h>
#include <boost/lexical_cast.hpp>
#include <iostream>

#include "lequation.h"

using namespace std;
using namespace llib;
using namespace boost;

class MySimulator : public llib::Simulator {
public:
    Float	x;

    MySimulator(): x(-0.5f) {}

    Boolean Render() {
        x += 0.001f;
        glClear(GL_COLOR_BUFFER_BIT); 
        glBegin(GL_TRIANGLES); 
        glVertex3f(x,-0.5,0.0); 
        glVertex3f(0.5,0.0,0.0); 
        glVertex3f(0.0,0.5,0.0); 
        glEnd(); 
        glFlush();
        return TRUE;
    }

    Boolean OnKeyDown(Uint8 key, Int32 x, Int32 y, Uint8 modifiers)	{
        cout << "OnKeyDown:" << endl
            << "key = " << key << ", x = " << x << ", y = " << y << ", m = " << Uint16(modifiers) << endl;
        return TRUE;
    }

    Boolean OnKeyUp(Uint8 key, Int32 x, Int32 y, Uint8 modifiers) {
        cout << "OnKeyUp:" << endl
            << "key = " << key << ", x = " << x << ", y = " << y << ", m = " << Uint16(modifiers) << endl;
        return TRUE;
    }

    Boolean OnSpecialKeyDown(Uint8 key, Int32 x, Int32 y, Uint8 modifiers) {
        cout << "OnSpecialKeyDown:" << endl
            << "key = " << Uint16(key) << ", x = " << x << ", y = " << y << ", m = " << Uint16(modifiers) << endl;
        return TRUE;
    }

    Boolean OnSpecialKeyUp(Uint8 key, Int32 x, Int32 y, Uint8 modifiers) {
        cout << "OnSpecialKeyUp:" << endl
            << "key = " << Uint16(key) << ", x = " << x << ", y = " << y << ", m = " << Uint16(modifiers) << endl;
        return TRUE;
    }

    Boolean Finalize() {
        cout << "MySimulator.Finalize() is called." << endl;
        return TRUE;
    }

};

#define DATA_SIZE		5000
#define RND_MAX			1000.f
#define RND_MIN			-1000.f

#include <fstream>

Boolean randomSampleData(string fileName)
{
    ofstream file(fileName.c_str());
    if(!file.is_open()) return FALSE;

    FOR(I,0,DATA_SIZE) {
        Float A = llib::math::RndRange(RND_MIN,RND_MAX);
        Float B = llib::math::RndRange(RND_MIN,RND_MAX);
        Float C = llib::math::RndRange(RND_MIN,RND_MAX);
        Float D = llib::math::RndRange(RND_MIN,RND_MAX);
        file << A << "\t" << B << "\t" << C  << "\t" << D << endl;
    }
    file.close();

    return TRUE;
}

Boolean sampleDataResCheck(string inputFileName, string outputFileName)
{
    ifstream file_input(inputFileName.c_str());
    ofstream file_output(outputFileName.c_str());
    if(!file_input.is_open() || !file_output.is_open()) {
        file_input.close();
        file_output.close();
        return FALSE;
    }

    FOR(I,0,DATA_SIZE) {
        Float A, B, C, D;
        file_input >> A >> B >> C >> D;
        //try {
        //	llib::math::EquationSolver::SolveCubicEquation(A,B,C,D);
        //} catch (llib::math::TmpException &e) {
        //	file_output << e.degree << "\t" << e.rootNum << endl;
        //}
    }

    file_input.close();
    file_output.close();
    return TRUE;
}

Boolean pickTriRootCubicEquationOut(string iEquationArgv, string iEquationCheck, string oPickout) {
    ifstream fArgv(iEquationArgv.c_str());
    ifstream fCheck(iEquationCheck.c_str());
    ofstream fPickout(oPickout.c_str());
    if(!fArgv.is_open() || !fCheck.is_open() || !fPickout.is_open()) {
        fArgv.close();
        fCheck.close();
        fPickout.close();
        return FALSE;
    }

    char line[1024];
    while(!fArgv.eof()) {
        fArgv.getline(line, 1024);
        int d, num;
        fCheck >> d >> num;
        if(num == 3) {
            fPickout << line << endl;
        }
    }

    fArgv.close();
    fCheck.close();
    fPickout.close();
    return TRUE;
}

#include <boost/progress.hpp>

Boolean runSpeedTimer(string inputFile) {
    vector<Float> As,Bs,Cs,Ds;
    // input
    {
        ifstream inputEquationFile(inputFile.c_str());
        if(!inputEquationFile.is_open()) return 0;
        Float A,B,C,D;
        while(!inputEquationFile.eof()) {
            inputEquationFile >> A >> B >> C >> D;
            As.push_back(A);
            Bs.push_back(B);
            Cs.push_back(C);
            Ds.push_back(D);
            if(As.size() == 1000) break;
        }
        inputEquationFile.close();
    }
    // time
    {
        int sz = Int32(As.size());
        boost::progress_timer timer;
        FOR(pass, 0, 4000) {
            FOR(I, 0, sz) {
                llib::math::EquationSolver::SolveCubicEquation(As[I], Bs[I], Cs[I], Ds[I]);
            }
        }
    }
    return TRUE;
}

Boolean resultOutput(string inputFile, string outputFile) {
    ifstream inputF(inputFile.c_str());
    ofstream outputF(outputFile.c_str());
    if(!inputF.is_open() || !outputF.is_open()) {
        inputF.close();
        outputF.close();
        return FALSE;
    }

    while(!inputF.eof()) {
        Float A, B, C, D;
        inputF >> A >> B >> C >> D;
        vector<Float> roots = llib::math::EquationSolver::SolveCubicEquation(A,B,C,D);
        FOR(I,0,SZ(roots)) {
            outputF << roots[I] << "\t";
        }
        outputF << endl;
    }



    inputF.close();
    outputF.close();
    return TRUE;
}

#define ARR_SZ	5

#include <algorithm>
#include <vector>

class classA {public: int A[5]; };

using namespace llib::geom;

class ClassB {
public:
    ClassB() { bool pause = true; }
};

#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>

class TestNonc : boost::noncopyable {
public:
    int a;
};

struct T {
    Int64& A;
};

class T2 {
public:
    T2(Int32 a) {}
};

void Test_old()
{
    //if(!randomSampleData("CubicEquationArgv.txt")) {
    //	cout << "Create file error" << endl;
    //}

    //if(!sampleDataResCheck("CubicEquationArgv.txt", "CubicEquationResCheck.txt")) {
    //	cout << "Check result error" << endl;
    //}

    //if(!pickTriRootCubicEquationOut("CubicEquationArgv.txt", "CubicEquationResCheck.txt", "CubicEquationTriRootPickout.txt")) {
    //	cout << "Pick out error" << endl;
    //}

    //if(!runSpeedTimer("CubicEquationTriRootPickout.txt")) {
    //	cout << "Run speed timer error" << endl;
    //}

    //if(!resultOutput("CubicEquationArgv.txt","CubicEquationRes_solution1.txt")) {
    //	cout << "Result output error" << endl;
    //}

    //Int32 arr_A[ARR_SZ] = { 0, 2, 7, 9, 11 };
    //Int32 arr_B[ARR_SZ] = { 1, 8, 10, 12, 13 };
    //vector<Int32> A(arr_A, arr_A + ARR_SZ);
    //vector<Int32> B(arr_B, arr_B + ARR_SZ);
    //vector<Int32> C(ARR_SZ * 2);
    //std::merge(A.begin(), A.end(), B.begin(), B.end(), C.begin());


    /* a small debug for in-place merge */
    //Int32 ArrInt[7] = { -5, -3, -1, 0, 1, 4, 9 };
    //vector<Int32> res(ArrInt, ArrInt + 6);
    //Int16 p = 0, sz = SZ(res);
    //FOR(I, 0, sz) {
    //	if(res[I] < 0) continue;
    //	if(res[I] > 2) break;
    //	res[p] = res[I];
    //	++p;
    //}
    //FOR(I, p, sz) res.pop_back();

    //vector<Int32> A;
    //A.push_back(1);
    //A.push_back(2);
    //vector<Int32> &B = A;
    //A = vector<Int32>();
    //B.push_back(3);

    //llib::geom::vec<int,2> a;
    //a.cell;
    //a.x;
    //a[0] = 0;
    //a[1] = a[0] + 1;
    //llib::geom::vec<int,2> bbbb = a * 2;

    //llib::geom::vec<Float,3> ttt;
    //ttt[0] = 0;
    //ttt[1] = 1;
    //ttt[2] = ttt[1] + 1;
    //llib::geom::vec<Float,3> tt2 = ttt + ttt;
    //Float t = tt2.Length();
    //tt2.Normalize();
    //t = tt2.Length();

    //llib::geom::vec<Float,3> tt3 = tt2.Cross(tt2);

    //Vec3f* point = new Vec3f[3];
    //point[0] = Vec3f(1.f,2.f,3.f);
    //point[1] = Vec3f(4.f,5.f,6.f);
    //point[2] = Vec3f(7.f,8.f,9.f);

    //Float* p = point[0].cell;
    //Float t;
    //FOR(I,0,9) t = *p++;

    //delete[] point;

    //vector<int> v(5);
    //FOR(I,0,5) v[I] = I;
    //int* p = &v[0];
    //FOR(I,0,5)
    //    ++p;

    //Int32 sz = sizeof(TestNonc);

    //shared_ptr<Int32> t;
    //Boolean isNull = (t == NULL);
}
